namespace ScrumSprintMonitor.UI.Wpf
{
	#region #using Directives

	using System;
	using System.Runtime.InteropServices;
	using System.Windows;
	using System.Windows.Controls;

	#endregion

	public class AnimatedWrapPanel : WrapPanel
	{
		// Using a DependencyProperty as the backing store for Duration.  This enables animation, styling, binding, etc...
		public static readonly DependencyProperty DurationProperty = DependencyProperty.Register("Duration", typeof(Duration), typeof(AnimatedStackPanel),
		                                                                                         new UIPropertyMetadata(
		                                                                                         	new Duration(new TimeSpan(0, 0, 0, 0, 500))));

		public Duration Duration
		{
			get { return (Duration) GetValue(DurationProperty); }
			set { SetValue(DurationProperty, value); }
		}

		/// <summary>
		/// Arranges the content of a <see cref="T:System.Windows.Controls.WrapPanel"/> element.
		/// </summary>
		/// <returns>
		/// The <see cref="T:System.Windows.Size"/> that represents the arranged size of this <see cref="T:System.Windows.Controls.WrapPanel"/> element and its children.
		/// </returns>
		/// <param name="finalSize">The <see cref="T:System.Windows.Size"/> that this element should use to arrange its child elements.
		///                 </param>
		protected override Size ArrangeOverride(Size finalSize)
		{
			int start = 0;
			double itemWidth = ItemWidth;
			double itemHeight = ItemHeight;
			double v = 0.0;
			double itemU = (Orientation == Orientation.Horizontal) ? itemWidth : itemHeight;
			var size = new UVSize(Orientation);
			var size2 = new UVSize(Orientation, finalSize.Width, finalSize.Height);
			bool flag = !DoubleUtil.IsNaN(itemWidth);
			bool flag2 = !DoubleUtil.IsNaN(itemHeight);
			bool useItemU = (Orientation == Orientation.Horizontal) ? flag : flag2;
			var internalChildren = base.InternalChildren;
			int end = 0;
			int count = internalChildren.Count;
			while (end < count)
			{
				var element = internalChildren[end];
				if (element != null)
				{
					var size3 = new UVSize(Orientation, flag ? itemWidth : element.DesiredSize.Width, flag2 ? itemHeight : element.DesiredSize.Height);
					if (DoubleUtil.GreaterThan(size.U + size3.U, size2.U))
					{
						arrangeLine(v, size.V, start, end, useItemU, itemU);
						v += size.V;
						size = size3;
						if (DoubleUtil.GreaterThan(size3.U, size2.U))
						{
							arrangeLine(v, size3.V, end, ++end, useItemU, itemU);
							v += size3.V;
							size = new UVSize(Orientation);
						}
						start = end;
					}
					else
					{
						size.U += size3.U;
						size.V = Math.Max(size3.V, size.V);
					}
				}
				end++;
			}
			if (start < internalChildren.Count)
			{
				arrangeLine(v, size.V, start, internalChildren.Count, useItemU, itemU);
			}
			return finalSize;
		}

		private void arrangeLine(double v, double lineV, int start, int end, bool useItemU, double itemU)
		{
			double num = 0.0;
			bool horizontal = Orientation == Orientation.Horizontal;
			var duration = Duration;
			var internalChildren = base.InternalChildren;
			for (int i = start; i < end; i++)
			{
				var element = internalChildren[i];
				if (element != null)
				{
					var size = new UVSize(Orientation, element.DesiredSize.Width, element.DesiredSize.Height);
					double u = useItemU ? itemU : size.U;
					AnimatedPanelHelper.ArrangeChild(this, element,
					                                 new Rect(horizontal ? num : v, horizontal ? v : num, horizontal ? u : lineV, horizontal ? lineV : u), duration);
					num += u;
				}
			}
		}

		#region Nested type: DoubleUtil

		private static class DoubleUtil
		{
			// Fields
			private const double DBL_EPSILON = 2.2204460492503131E-16;

			// Methods
			private static bool AreClose(double value1, double value2)
			{
				if (value1 == value2)
				{
					return true;
				}
				double num = ((Math.Abs(value1) + Math.Abs(value2)) + 10.0) * DBL_EPSILON;
				double num2 = value1 - value2;
				return ((-num < num2) && (num > num2));
			}

			internal static bool GreaterThan(double value1, double value2)
			{
				return ((value1 > value2) && !AreClose(value1, value2));
			}

			internal static bool IsNaN(double value)
			{
				var union = new NanUnion
				            	{
				            		DoubleValue = value
				            	};
				ulong num = union.UintValue & 18442240474082181120L;
				ulong num2 = union.UintValue & (0xfffffffffffffL);
				if ((num != 0x7ff0000000000000L) && (num != 18442240474082181120L))
				{
					return false;
				}
				return (num2 != 0L);
			}

			// Nested Types

			#region Nested type: NanUnion

			[StructLayout(LayoutKind.Explicit)]
			private struct NanUnion
			{
				// Fields
				[FieldOffset(0)] internal double DoubleValue;
				[FieldOffset(0)] internal ulong UintValue;
			}

			#endregion
		}

		#endregion

		#region Nested type: UVSize

		[StructLayout(LayoutKind.Sequential)]
		private struct UVSize
		{
			internal double U;
			internal double V;
			private readonly Orientation _orientation;

			internal UVSize(Orientation orientation, double width, double height)
			{
				this.U = this.V = 0.0;
				this._orientation = orientation;
				Width = width;
				Height = height;
			}

			internal UVSize(Orientation orientation)
			{
				this.U = this.V = 0.0;
				this._orientation = orientation;
			}

			private double Width
			{
				get
				{
					if (this._orientation != Orientation.Horizontal)
					{
						return this.V;
					}
					return this.U;
				}
				set
				{
					if (this._orientation == Orientation.Horizontal)
					{
						this.U = value;
					}
					else
					{
						this.V = value;
					}
				}
			}

			private double Height
			{
				get
				{
					if (this._orientation != Orientation.Horizontal)
					{
						return this.U;
					}
					return this.V;
				}
				set
				{
					if (this._orientation == Orientation.Horizontal)
					{
						this.V = value;
					}
					else
					{
						this.U = value;
					}
				}
			}
		}

		#endregion
	}
}